package com.misboot.document.service.impl;

import cn.ewsd.common.utils.JsonUtils;
import cn.ewsd.common.utils.StringUtils;
import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.*;
import com.misboot.document.client.SystemClient;
import com.misboot.document.model.DfsFile;
import com.misboot.document.model.OssObject;
import com.misboot.document.model.OssPageParam;
import com.misboot.document.service.OssService;
import com.misboot.document.utils.PageUtil.PageParam;
import com.misboot.document.utils.PageUtil.PageSet;
import com.misboot.document.utils.file.FileUtils;
import org.apache.commons.collections4.map.HashedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service("OssServiceImpl")
public class OssServiceImpl extends DocumentBaseServiceImpl<DfsFile, String> implements OssService {

    private static final Logger LOGGER = LoggerFactory.getLogger(DocumentBaseServiceImpl.class);

    @Value("${spring.oss.access-key-secret}")
    private String ACCESS_KEY_SECRET;

    @Value("${spring.oss.access-key}")
    private String ACCESS_KEY_ID;

    private OSSClient ossClient; // 开启后记得关闭


    @Autowired
    private SystemClient sysAuthDataClient;

    @Override
    public List<Bucket> listBuckets(String endpoint) {
        // 创建OSSClient实例。
        this.openOssClient(endpoint);
        ListBucketsRequest listBucketsRequest = new ListBucketsRequest();
        listBucketsRequest.setMaxKeys(500); // 设置最大查询数量
        List<Bucket> buckets = ossClient.listBuckets();
        // 去除掉没有权限的bucket
        List<Bucket> newBuckets = new ArrayList<Bucket>();

        for (int i = 0; i < buckets.size(); i++) {
            String extranetEndpoint = buckets.get(i).getExtranetEndpoint();
            String name = buckets.get(i).getName();
            //String bucketAcl = this.getBucketsAcl(extranetEndpoint, name);
            if (!name.equals("zysd-emis")) {
                newBuckets.add(buckets.get(i));
            }

            //if(!bucketAcl.equals("private")){
            //    newBuckets.add(buckets.get(i));
            //}
            //System.out.println("=========="+bucketsAcl);
        }
        // 关闭服务
        ossClient.shutdown();
        return newBuckets;
    }

    /**
     * @MethodName getBucketsAcl
     * @Description 获取bucket
     * @Param endpoint
     * @Param bucketName
     * @Return java.lang.String
     * @Author 宋景民<songjingmin @ zuoyoutech.com>
     * @Date 2019/4/29 9:43
     */
    public String getBucketsAcl(String endpoint, String bucketName) {
        OSSClient client = null;
        try {
            //TODO 湖南佐佑时代科技有限公司 当开启自动获取配置的时候 放开下面4行注释代码
            Map<String, Object> otherMap = sysAuthDataClient.getSysConfigurationDetailByType("other");
            String accessKey = ACCESS_KEY_ID;
            String accessKeySecret = ACCESS_KEY_SECRET;
            if ("true".equals(otherMap.get("state").toString())) {
                Map<String, Object> map = sysAuthDataClient.getSysConfigurationDetailByType("fileUpload");
                accessKey = map.get("accessKey").toString();
                accessKeySecret = map.get("accessKeySecret").toString();
            }
            client = new OSSClient(endpoint, accessKey, accessKeySecret);
            AccessControlList bucketAcl = client.getBucketAcl(bucketName);
            return bucketAcl.getCannedACL().toString();
        } catch (Exception e) {
            return null;
        } finally {
            client.shutdown();
        }
    }

    public void openOssClient(String endpoint) {
        if (ossClient != null) {
            ossClient.shutdown();
        }
        // 保存oss对象
        //TODO 湖南佐佑时代科技有限公司 当开启自动获取配置的时候 放开下面4行注释代码
        Map<String, Object> otherMap = sysAuthDataClient.getSysConfigurationDetailByType("other");
        String accessKey = ACCESS_KEY_ID;
        String accessKeySecret = ACCESS_KEY_SECRET;
        if ("true".equals(otherMap.get("state").toString())) {
            Map<String, Object> map = sysAuthDataClient.getSysConfigurationDetailByType("fileUpload");
            accessKey = map.get("accessKey").toString();
            accessKeySecret = map.get("accessKeySecret").toString();
        }

        ossClient = new OSSClient(endpoint, accessKey, accessKeySecret);  //当开启自动获取配置的时注释掉
    }

    @Override
    public PageSet<DfsFile> getPageSet(PageParam pageParam, String filterSort) {
        return null;
    }

    @Override
    public DfsFile queryObject(String uuid) {
        return null;
    }

    @Override
    public List<DfsFile> queryList(Map<String, Object> map) {
        return null;
    }

    @Override
    public int queryTotal(Map<String, Object> map) {
        return 0;
    }

    @Override
    public int executeSave(DfsFile dfsFile) {
        return 0;
    }

    @Override
    public int executeUpdate(DfsFile dfsFile) {
        return 0;
    }

    @Override
    public int executeDelete(String uuid) {
        return 0;
    }

    @Override
    public int executeDeleteBatch(String[] uuids) {
        return 0;
    }

    /**
     * @MethodName listObjectsRequest
     * @Description 宋景民分页查询并列出文件对象
     * @Param pageParam
     * @Param bucketName
     * @Param endpoint
     * @Return void
     * @Author 宋景民<songjingmin @ zuoyoutech.com>
     * @Date 2019/4/26 14:09
     */
    @Override
    public Map<String, Object> listObjectsRequest(OssPageParam ossPageParam, String search) {
        //打开client链接
        this.openOssClient(ossPageParam.getEndpoint());


        final int maxKeys = ossPageParam.getMaxKeys() == 0 ? 100 : ossPageParam.getMaxKeys(); // 当前页最大文件个数
        String nextMarker = ossPageParam.getNextMarker(); // 记录最后一个文件，用于分页
        final String keyPrefix = (ossPageParam.getKeyPrefix() == null || ossPageParam.getKeyPrefix().trim().isEmpty()) ? "" : ossPageParam.getKeyPrefix(); // 指定前缀。


        ListObjectsRequest listObjectsRequest = new ListObjectsRequest(ossPageParam.getBucketName());
        // 设置正斜线（/）为文件夹的分隔符。
        listObjectsRequest.setDelimiter("/");
        // 列出目录下的所有文件和文件夹。
        if (keyPrefix != null) {
            if (search != null)
                listObjectsRequest.setPrefix(keyPrefix + search.trim());
        }
        // 设置最大值
        listObjectsRequest.setMaxKeys(maxKeys);
        if (nextMarker != null) {
            listObjectsRequest.setMarker(nextMarker); // 设置下一页的分隔符
        }
        ObjectListing objectListing = ossClient.listObjects(listObjectsRequest);

        // 封装返回值
        Map<String, Object> resultMap = new HashedMap<String, Object>();
        resultMap.put("nextMarker", objectListing.getNextMarker());
        resultMap.put("keyPrefix", keyPrefix);
        resultMap.put("maxKeys", maxKeys);

        List<OssObject> ossObjectList = new ArrayList<OssObject>();
        resultMap.put("rows", ossObjectList);

        OssObject ossObject = null;
        // 遍历所有commonPrefix。

        for (String commonPrefix : objectListing.getCommonPrefixes()) {
            ossObject = new OssObject();
            ossObject.setUuid(commonPrefix);
            ossObject.setObjectName(commonPrefix);
            ossObject.setIsFile(false);
            ossObject.setBucketName(ossPageParam.getBucketName());
            ossObject.setEndpoint(ossPageParam.getEndpoint());
            ossObjectList.add(ossObject);
        }
        for (OSSObjectSummary s : objectListing.getObjectSummaries()) {
            //注意此处去除目录的本身
            if (!s.getKey().equals(keyPrefix)) {
                ossObject = new OssObject();
                ossObject.setUuid(s.getKey()); // 设置唯一 标识为Key也就是 ojectName
                ossObject.setKey(s.getKey()); // ojectName
                ossObject.setObjectName(s.getKey()); // ojectName
                ossObject.setSize(FileUtils.getSize(s.getSize())); // 大小
                ossObject.setBucketName(s.getBucketName());
                ossObject.setEndpoint(ossPageParam.getEndpoint());
                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                ossObject.setUpdateTime(formatter.format(s.getLastModified())); // 修改时间
                ossObject.setKeyPrefix(keyPrefix); // 获得 Key的前缀
                ossObject.setIsFile(true); //  是文件夹还是文件
                ossObject.setStorageClass(s.getStorageClass());//  存储类型

                ossObjectList.add(ossObject);
            }
        }

        // 关闭OSSClient。
        ossClient.shutdown();
        return resultMap;
    }


    @Override
    public String getObjectACL(String objectName, String endpoint, String bucketName) {
        openOssClient(endpoint);

        //// 获取文件的访问权限。
        ObjectAcl objectAcl = ossClient.getObjectAcl(bucketName, objectName);
        String permission = objectAcl.getPermission().toString();
        // 关闭OSSClient。
        ossClient.shutdown();
        return permission;
    }

    @Override
    public String getBucketACL(String endpoint, String bucketName) {
        openOssClient(endpoint);

        //// 获取文件的访问权限。
        AccessControlList accessControlList = ossClient.getBucketAcl(bucketName);


        // 关闭OSSClient。
        ossClient.shutdown();
        return accessControlList.getCannedACL().toString();
    }

    @Override
    public URL getGeneratePresignedUrl(String bucketName, String endpoint, String objectName, Date expiration) {
        openOssClient(endpoint);


        // 生成以GET方法访问的签名URL，访客可以直接通过浏览器访问相关内容。
        URL url = ossClient.generatePresignedUrl(bucketName, objectName, expiration);
        // 关闭OSSClient。
        ossClient.shutdown();
        return url;
    }

    @Override
    public OSSClient getOssClient() {
        return ossClient;
    }

    @Override
    public List<String> deleteObjects(String[] objects, String endpoint, String bucketName) {
        openOssClient(endpoint);

        List<String> keys = new ArrayList<String>();
        for (String objectName : objects) {
            if (objectName.endsWith("/")) {
                // 指定每页200个文件。
                final int maxKeys = 200;
                final String keyPrefix = objectName;
                String nextMarker = "";
                ObjectListing objectListing;

                do {
                    objectListing = ossClient.listObjects(new ListObjectsRequest(bucketName).
                            withPrefix(keyPrefix).withMarker(nextMarker).withMaxKeys(maxKeys));

                    List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
                    for (OSSObjectSummary s : sums) {
                        keys.add(s.getKey());
                    }

                    nextMarker = objectListing.getNextMarker();

                } while (objectListing.isTruncated());
            }
            keys.add(objectName);
        }

        DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(new DeleteObjectsRequest(bucketName).withKeys(keys));
        List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();

        ossClient.shutdown();
        return deletedObjects;
    }

    @Override
    public void putObject(String bucketName, String endpoint, String objectName, byte[] content) {

        try {
            openOssClient(endpoint);

            // 上传内容到指定的存储空间（bucketName）并保存为指定的文件名称（objectName）。
            ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content));

            // 关闭OSSClient。
            ossClient.shutdown();
        } catch (Exception e) {
            LOGGER.info("错误===" + e.getMessage());
        }
    }

    @Override
    public void CreateFolder(String endpoint, String bucketName, String catalog, String keyPrefix) {
        openOssClient(endpoint);

        /*
         * Create an empty folder without request body, note that the key must be
         * suffixed with a slash
         */
        catalog = catalog.endsWith("/") ? catalog : catalog + "/";
        String keySuffixWithSlash = catalog;
        if (!StringUtils.isNullOrEmpty(keyPrefix) && !"undefined".equals(keyPrefix)) {
            keySuffixWithSlash = keyPrefix + catalog;
        }
        ossClient.putObject(bucketName, keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));

        ossClient.shutdown();

    }

    @Override
    public void putObjectACL(String bucketName, String endpoint, String objectName, byte[] content) {
        openOssClient(endpoint);

        // 上传内容到指定的存储空间（bucketName）并保存为指定的文件名称（objectName）。
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new ByteArrayInputStream(content));
        // 设置公共访问
        Map<String, String> headMap = new HashedMap<String, String>();
        headMap.put("x-oss-object-acl", "public-read");
        putObjectRequest.setHeaders(headMap);

        ossClient.putObject(putObjectRequest);


        // 关闭OSSClient。
        ossClient.shutdown();
    }

    @Override
    public Object ossFileMoveBucket(String sourceBucketName, String sourceKey, String destinationBucketName, String endpoint) {
        if (StrUtil.isBlank(sourceBucketName) || StrUtil.isBlank(sourceKey) || StrUtil.isBlank(destinationBucketName) ||StrUtil.isBlank(endpoint)) {
            return JsonUtils.messageJson(300, "操作提示", "请检查sourceBucketName/sourceKey/destinationBucketName/endpoint不能为空!!!");
        }

        String str[] = sourceKey.split(",");
        for (String strs : str) {
            openOssClient(endpoint);

            String destinationKey = strs; //http://zysd-test2.zysd-test2/test.docx  //test.docx

            ObjectMetadata objectMetadata = ossClient.getObjectMetadata(sourceBucketName, strs);
            // 获取被拷贝文件的大小。
            long contentLength = objectMetadata.getContentLength();

            // 设置分片大小为10 MB。单位为字节。
            long partSize = 1024 * 1024 * 10;

            // 计算分片总数。
            int partCount = (int) (contentLength / partSize);
            if (contentLength % partSize != 0) {
                partCount++;
            }
            System.out.println("total part count:" + partCount);

            // 初始化拷贝任务。可以通过InitiateMultipartUploadRequest指定目标文件元信息。
            InitiateMultipartUploadRequest initiateMultipartUploadRequest = new InitiateMultipartUploadRequest(destinationBucketName, destinationKey);
            InitiateMultipartUploadResult initiateMultipartUploadResult = ossClient.initiateMultipartUpload(initiateMultipartUploadRequest);
            String uploadId = initiateMultipartUploadResult.getUploadId();

            // 分片拷贝。
            List<PartETag> partETags = new ArrayList<PartETag>();
            for (int i = 0; i < partCount; i++) {
                // 计算每个分片的大小。
                long skipBytes = partSize * i;
                long size = partSize < contentLength - skipBytes ? partSize : contentLength - skipBytes;

                // 创建UploadPartCopyRequest。可以通过UploadPartCopyRequest指定限定条件。
                UploadPartCopyRequest uploadPartCopyRequest =
                        new UploadPartCopyRequest(sourceBucketName, strs, destinationBucketName, destinationKey);
                uploadPartCopyRequest.setUploadId(uploadId);
                uploadPartCopyRequest.setPartSize(size);
                uploadPartCopyRequest.setBeginIndex(skipBytes);
                uploadPartCopyRequest.setPartNumber(i + 1);
                UploadPartCopyResult uploadPartCopyResult = ossClient.uploadPartCopy(uploadPartCopyRequest);

                // 将返回的分片ETag保存到partETags中。
                partETags.add(uploadPartCopyResult.getPartETag());
            }
            // 提交分片拷贝任务。
            CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(
                    destinationBucketName, destinationKey, uploadId, partETags);
            ossClient.completeMultipartUpload(completeMultipartUploadRequest);
            LOGGER.info("文件" + strs + "由" + sourceBucketName + "复制到" + destinationBucketName + "成功");

            // 删除文件。如需删除文件夹，请将ObjectName设置为对应的文件夹名称。如果文件夹非空，则需要将文件夹下的所有object删除后才能删除该文件夹。
            deleteObjects(new String[]{strs}, endpoint, sourceBucketName);
            LOGGER.info("文件" + strs + "在桶" + sourceBucketName + "删除成功");
            ossClient.shutdown();

        }


        return JsonUtils.messageJson(200, "操作提示", "移动成功");
    }

    @Override
    public Object ossFileMoveFolder(String sourceBucketName, String sourceKey, String destinationBucketName, String endpoint, String destinationKey) {
        if(StrUtil.isBlank(destinationKey)){
            return JsonUtils.messageJson(300, "操作提示", "目标文件名称destinationKey不能为空!!!");
        }
        if(destinationKey.contains("undefined")){
            return JsonUtils.messageJson(300, "操作提示", "请进入目录中进行粘贴！！！");
        }
        if(StrUtil.isAllBlank(sourceBucketName,sourceKey,destinationBucketName,endpoint,destinationKey)){
            return JsonUtils.messageJson(300, "操作提示", "请检查sourceBucketName/sourceKey/destinationBucketName/endpoint/destinationKey不能为空!!!");
        }
        String sourceKeyStr[] = sourceKey.split(",");
        String destinationKeyStr[] = destinationKey.split(",");
        for (int i = 0; i < sourceKeyStr.length; i++) {
            openOssClient(endpoint);
            CopyObjectResult result = ossClient.copyObject(sourceBucketName, sourceKeyStr[i], destinationBucketName, destinationKeyStr[i]);
            LOGGER.info("文件" + sourceKeyStr[i] + "复制到" + sourceBucketName + "/" + destinationKey + "成功");
            deleteObjects(new String[]{sourceKeyStr[i]}, endpoint, sourceBucketName);
            LOGGER.info("文件" + sourceKeyStr[i] + "在桶" + sourceBucketName + "删除成功");
            ossClient.shutdown();
        }
        return JsonUtils.messageJson(200, "操作提示", "移动成功");
    }

}
